package cn.agiledata.bank.transaction.action;

import java.math.BigDecimal;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import cn.agiledata.bank.account.facade.AccountFacade;
import cn.agiledata.bank.audit.exception.AuditException;
import cn.agiledata.bank.common.dao.AccountTemplateInter;
import cn.agiledata.bank.common.service.PermissionService;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.ForeDict;
import cn.agiledata.bank.common.util.PageBean;
import cn.agiledata.bank.common.util.WeatherUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.transaction.exception.TransactionException;
import cn.agiledata.bank.transaction.facade.TransactionFacade;
import cn.agiledata.bank.transaction.form.BatchPayForm;
import cn.agiledata.bank.transaction.form.MultiStepForm;
import cn.agiledata.bank.transaction.logic.BatchPeerAccount;
import cn.agiledata.bank.transaction.service.TransactionService;
import com.vnv.infrastructure.action.IPBBaseAction;
import com.vnv.infrastructure.exception.IPBAppException;
import com.vnv.infrastructure.logic.IPBAppFactory;

public class BatchPayAction extends IPBBaseAction {
    private AccountFacade accountFacade;

    private TransactionFacade transactionFacade;

    private TransactionService transactionService;

    private AccountFacade getAccountFacade() {
        if (this.accountFacade == null) {
            this.accountFacade = (AccountFacade) IPBAppFactory
                    .getObj(ForeDict.FACADE_ACCOUNT);
        }
        return this.accountFacade;
    }

    private TransactionFacade getTransactionFacade() {
        if (this.transactionFacade == null) {
            this.transactionFacade = (TransactionFacade) IPBAppFactory
                    .getObj(ForeDict.FACADE_TRANSACTION);
        }
        return this.transactionFacade;
    }

    private TransactionService getTransactionService() {
        if (this.transactionService == null) {
            this.transactionService = (TransactionService) IPBAppFactory
                    .getObj(ForeDict.SERVICE_TRANSACTION);
        }
        return this.transactionService;
    }

    /**
     * 分发调度
     */
    public final ActionForward assign(ActionMapping mapping,
            ActionForm actionForm, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        MultiStepForm form = (MultiStepForm) actionForm;
        int step = form.getStep();
        ActionForward forward;
        switch (step) {
        case 0: // 第0步准备初始化数据
            forward = prepare(mapping, actionForm, request, response);
            break;
        case 1: // 第1步填写批量支付信息
            forward = fill(mapping, actionForm, request, response);
            break;
        case 2: // 第2步进行批量支付，显示支付结果
            forward = pay(mapping, actionForm, request, response);
            break;
        default:
            // 其它步骤序数跳转到第0步，进入新的批量支付流程，防止错误的步骤序数被提交。
            // 可利用此特性，通过传入小于0的步骤序数，将session范围的Form重置
            form.setStep(0);
            form.reset(mapping, request);
            forward = prepare(mapping, actionForm, request, response);
        }
        // 设置新的步骤序数，最大步骤序数为2
        form.setNextStep(2);
        return forward;
    }

    private final AccountTemplateInter getAccountTemplate() {
        return (AccountTemplateInter) IPBAppFactory
                .getObj(ForeDict.ACCOUNT_TEMPLATE);
    }

    /**
     * 获取当前账户
     */
    private final Account getCurrentAccount(HttpServletRequest request) {
        long accountId = WeatherUtil.getAccountIdFromSession(request);
        return getAccountTemplate().getAccount(String.valueOf(accountId));
    }

    /**
     * 判断指定用户是否个人用户
     */
    private final boolean isPersonAccount(Account account) {
        return Constant.ACCOUNT_TYPE_BUYER.equals(account.getAccountType());
    }

    /**
     * 加载子账户列表
     */
    private final void loadSubAccountList(HttpServletRequest request) {
        Account account = getCurrentAccount(request);
        SubAccount defaultSubAccount = account.getDefaultSubAccount();
        if (isPersonAccount(account)) { // 个人用户
            // 获取当前个人用户的所有子账户列表
            Set subAccounts = account.getSubAccounts();
            request.setAttribute("subAccounts", subAccounts);
        } else { // 企业操作员
            // 获取当前企业操作员具有提现权限的子账户列表
            List subAccounts = PermissionService.getPermissionService()
                    .getSubAccounts(request, Constant.PERMIS_TYPE_PAYMONEY,
                            defaultSubAccount);
            request.setAttribute("subAccounts", subAccounts);
        }
    }

    public ActionForward prepare(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        Account account = getAccountFacade().currentAccount(request);
        // 判断当前用户是否具有付款的权限
        if (!getAccountFacade().hasPermission(request,
                Constant.PERMIS_TYPE_PAYMONEY)) {
            handleAppException(mapping, actionForm, request, response,
                    TransactionException.NO_PERMISSION);
        }
        loadSubAccountList(request);
        // 付款子账户默认选择默认子账户
        BatchPayForm form = (BatchPayForm) actionForm;
        if (form.getSubAccountId() == 0) {
            SubAccount defaultSubAccount = account.getDefaultSubAccount();
            form.setSubAccountId(defaultSubAccount.getId().longValue());
        }
        request.setAttribute("batchPeerAccount", form.getBatchPeerAccount());
        return mapping.findForward(ForeDict.FORWARD_STEP_1);
    }

    public ActionForward fill(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        BatchPayForm form = (BatchPayForm) actionForm;
        BatchPeerAccount batchPeerAccount = form.getBatchPeerAccount();
        request.setAttribute("batchPeerAccount", batchPeerAccount);
        try {
        	String subAccountId = String.valueOf(form.getSubAccountId());
            SubAccount subAcc = getAccountTemplate()
                    .getSubAccount(subAccountId);
        	Account account = subAcc.getAccount();
        	Account curAccount = getCurrentAccount(request);
        	if (!curAccount.equals(account)) {
            	throw TransactionException.NOT_THE_SAME_ACCOUNT;
            }
            // 判断当前用户是否具有付款的权限
            if (!getAccountFacade().hasPermission(request,
                    Constant.PERMIS_TYPE_PAYMONEY)) {
                throw TransactionException.NO_PERMISSION;
            }

            if (batchPeerAccount == null || batchPeerAccount.getCount() == 0) { // 未设置交易对方账户
                throw TransactionException.NO_PEER_ACCOUNT;
            }
            // 校验子账户余额
            BigDecimal amount = batchPeerAccount.getTotalAmountWithFee();
            SubAccount subAccount = getTransactionFacade().validateBalance(
                    form.getSubAccountId(), amount);
            request.setAttribute("subAccount", subAccount);
            // 校验B2C限制
            getTransactionService().validateBatchTransactable(
                    subAccount.getAccount(), batchPeerAccount);
        } catch (TransactionException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            // 跳转到第1步，之前重新装载子账户列表
            loadSubAccountList(request);
            // 设置为上一步的步骤序数，防止序数与步骤不同步
            form.setPreviousStep();
            return mapping.findForward(ForeDict.FORWARD_STEP_1);
        }
        return mapping.findForward(ForeDict.FORWARD_STEP_2);
    }

    public ActionForward pay(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        BatchPayForm form = (BatchPayForm) actionForm;
        BatchPeerAccount batchPeerAccount = form.getBatchPeerAccount();
        request.setAttribute("batchPeerAccount", batchPeerAccount);
        try {
            if (batchPeerAccount == null || batchPeerAccount.getCount() == 0) { // 未设置交易对方账户
                throw TransactionException.NO_PEER_ACCOUNT;
            }
            String subAccountId = String.valueOf(form.getSubAccountId());
            SubAccount subAcc = getAccountTemplate()
                    .getSubAccount(subAccountId);
        	Account account = subAcc.getAccount();
        	Account curAccount = getCurrentAccount(request);
        	if (!curAccount.equals(account)) {
            	throw TransactionException.NOT_THE_SAME_ACCOUNT;
            }
            // 校验子账户余额
            BigDecimal amount = batchPeerAccount.getTotalAmountWithFee();
            SubAccount subAccount = getTransactionFacade().validateBalance(
                    form.getSubAccountId(), amount);
            // 校验B2C限制
            getTransactionService().validateBatchTransactable(
                    subAccount.getAccount(), batchPeerAccount);

            String batchNo = "";
            // 加载页面参数
            request.setAttribute("batchNo", batchNo);
            request.setAttribute("subAccount", subAccount);
            request.setAttribute("purpose", form.getPurpose());
        } catch (IPBAppException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            if (e instanceof AuditException) {
                // 如果保存批量支付交易过程中产生审核异常，则跳转到全局错误页面
                request.setAttribute("bundle", "audit");
                return mapping.findForward(FORWARD_GLOBAL_ERROR);
            }
            // 跳转到第2步，之前重新装载子账户
            loadSubAccount(request, form);
            // 设置为上一步的步骤序数，防止序数与步骤不同步
            form.setPreviousStep();
            return mapping.findForward(ForeDict.FORWARD_STEP_2);
        }
        return mapping.findForward(ForeDict.FORWARD_STEP_3);
    }

    public ActionForward input(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        BatchPayForm form = (BatchPayForm) actionForm;
        // 加载子账户
        loadSubAccount(request, form);
        // 处理账户类型
        String type = form.getType();
        if (StringUtils.isEmpty(type)) {
            type = Constant.BATCH_PAY_TYPE_INNER; // 默认内部账户
        }
        BatchPeerAccount bpa = form.getBatchPeerAccount();
        if (bpa == null) {
            bpa = BatchPeerAccount.getInnerBatchPeerAccount(); // 默认内部账户
        }
        if (Constant.BATCH_PAY_TYPE_INNER.equals(type)
                && bpa.isBankBatchPeerAccount()) {
            // 从银行账户切换到内部账户
            bpa = BatchPeerAccount.getInnerBatchPeerAccount();
        } else if (Constant.BATCH_PAY_TYPE_BANK.equals(type)
                && bpa.isInnerBatchPeerAccount()) {
            // 从内部账户切换到银行账户
            bpa = BatchPeerAccount.getBankBatchPeerAccount();
        }
        form.setType(type);
        form.setBatchPeerAccount(bpa);
        // 查询交易对方账户列表
        String startPage = request.getParameter("startPage");
        if (StringUtils.isEmpty(startPage)) {
            startPage = "1"; // 默认显示第1页
        }
        String pageRecord = request.getParameter("pageRecord");
        if (StringUtils.isEmpty(pageRecord)) {
            pageRecord = "10"; // 默认每页显示10条
        }
        Long accountId = getAccountFacade().currentAccount(request).getId();
        PageBean pb = getTransactionFacade().getPeerAccountList(accountId, bpa,
                startPage, pageRecord);
        // 加载页面属性参数
        request.setAttribute("result", pb);
        request.setAttribute("type", type);
        request.setAttribute("batchPeerAccount", bpa);
        loadFeeModeDescription(request, bpa);

        return mapping.findForward(FORWARD_SUCCESS);
    }

    public ActionForward view(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        BatchPayForm form = (BatchPayForm) actionForm;
        // 加载子账户
        loadSubAccount(request, form);

        BatchPeerAccount bpa = form.getBatchPeerAccount();
        request.setAttribute("batchPeerAccount", bpa);
        // 查询已设置的交易对方账户及金额列表
        String startPage = request.getParameter("startPage");
        if (StringUtils.isEmpty(startPage)) {
            startPage = "1"; // 默认显示第1页
        }
        String pageRecord = request.getParameter("pageRecord");
        if (StringUtils.isEmpty(pageRecord)) {
            pageRecord = "10"; // 默认每页显示10条
        }
        PageBean pb = getTransactionFacade().getPeerAccountAmountList(bpa,
                Integer.parseInt(startPage), Integer.parseInt(pageRecord));
        request.setAttribute("result", pb);
        loadFeeModeDescription(request, bpa);

        return mapping.findForward(FORWARD_SUCCESS);
    }

    /**
     * 加载子账户
     */
    private SubAccount loadSubAccount(HttpServletRequest request,
            BatchPayForm form) {
        long subAccountId = form.getSubAccountId();
        SubAccount subAccount = getAccountFacade().getSubAccountById(
                subAccountId);
        request.setAttribute("subAccount", subAccount);
        return subAccount;
    }

    /**
     * 加载收费方式描述
     */
    private void loadFeeModeDescription(HttpServletRequest request,
            BatchPeerAccount batchPeerAccount) {
        Account account = getAccountFacade().currentAccount(request);
        String feeMode = "";
        if (batchPeerAccount != null) {
            String actionType = batchPeerAccount.isInnerBatchPeerAccount() ? Constant.ACTION_TYPE_C
                    : Constant.ACTION_TYPE_G;
            feeMode = getTransactionFacade().getFeeModeDescription(account,
                    actionType);
        }
        request.setAttribute("feeMode", feeMode);
    }
}
